package io.renren.modules.workmanagement.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.renren.common.exception.RRException;
import io.renren.common.utils.PageUtils;
import io.renren.common.utils.Query;
import io.renren.modules.sys.entity.SysRoleEntity;
import io.renren.modules.sys.entity.SysUserEntity;
import io.renren.modules.sys.service.SysRoleService;
import io.renren.modules.sys.service.SysUserRoleService;
import io.renren.modules.sys.service.SysUserService;
import io.renren.modules.workmanagement.constans.UserConstans;
import io.renren.modules.workmanagement.dao.ClassCourseDao;
import io.renren.modules.workmanagement.entity.*;
import io.renren.modules.workmanagement.enums.RoleEnums;
import io.renren.modules.workmanagement.enums.WorkStatusEnum;
import io.renren.modules.workmanagement.service.*;
import io.renren.modules.workmanagement.utils.PojoUtils;
import io.renren.modules.workmanagement.vo.ClassCourse.*;
import io.renren.modules.workmanagement.vo.MyClassVO;
import io.renren.modules.workmanagement.vo.SubmitWork;
import io.renren.modules.workmanagement.vo.WorkDetail;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;


@Service("classCourseService")
public class ClassCourseServiceImpl extends ServiceImpl<ClassCourseDao, ClassCourseEntity> implements ClassCourseService {
    @Autowired
    private DepartmentService departmentService;
    @Autowired
    private ClassService classService;
    @Autowired
    private CourseService courseService;
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private WorkService workService;
    @Autowired
    private QuestionBankService questionBankService;
    @Autowired
    private StudentService studentService;
    @Autowired
    private WorkFinishStatusDetailService workFinishStatusDetailService;
    @Autowired
    private SysRoleService sysRoleService;
    @Autowired
    private SysUserRoleService sysUserRoleService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        Long userId = (Long) params.get(UserConstans.USER_ID_KEY);
        LambdaQueryWrapper<ClassCourseEntity> wrapper = new LambdaQueryWrapper<>();
        String key = (String) params.get("key");
        if(StringUtils.isNotBlank(key)){
            List<ClassEntity> classes = classService.likeByName(key);
            List<CourseEntity> courses = courseService.likeByName(key);
            List<SysUserEntity> userEntityList = sysUserService.likeByName(key);
            if(CollectionUtil.isNotEmpty(classes)){
                List<Long> classIds = PojoUtils.streamMapList(classes, ClassEntity::getId);
                wrapper.in(ClassCourseEntity::getClassId, classIds);
            }
            if(CollectionUtil.isNotEmpty(courses)){
                List<Long> courseIds = PojoUtils.streamMapList(courses, CourseEntity::getId);
                wrapper.in(ClassCourseEntity::getCourseId, courseIds);
            }
            if(CollectionUtil.isNotEmpty(userEntityList)){
                List<Long> userIds = PojoUtils.streamMapList(userEntityList, SysUserEntity::getUserId);
                wrapper.in(ClassCourseEntity::getTeacherId, userIds);
            }
        }
        DepartmentEntity department = departmentService.getByAdminId(userId);
        IPage<ClassCourseEntity> page = this.page(
                new Query<ClassCourseEntity>().getPage(params),
                wrapper.eq(ClassCourseEntity::getDepartmentId, department.getId())
        );
        List<ClassCourseEntity> records = page.getRecords();
        List<Long> classIds = records.stream().map(ClassCourseEntity::getClassId).collect(Collectors.toList());
        List<Long> courseIds = records.stream().map(ClassCourseEntity::getCourseId).collect(Collectors.toList());
        List<Long> teacherIds = records.stream().map(ClassCourseEntity::getTeacherId).collect(Collectors.toList());
        Map<Long, ClassEntity> classEntityMap = classService.listByIds(classIds).stream().collect(Collectors.toMap(ClassEntity::getId, Function.identity()));
        Map<Long, CourseEntity> courseEntityMap = courseService.listByIds(courseIds).stream().collect(Collectors.toMap(CourseEntity::getId, Function.identity()));
        Map<Long, SysUserEntity> sysUserEntityMap = sysUserService.listByIds(teacherIds).stream().collect(Collectors.toMap(SysUserEntity::getUserId, Function.identity()));
        List<CourseVO> courseVOS = records.stream().map(item -> {
            ClassEntity classEntity = classEntityMap.get(item.getClassId());
            CourseEntity courseEntity = courseEntityMap.get(item.getCourseId());
            SysUserEntity sysUserEntity = sysUserEntityMap.get(item.getTeacherId());
            CourseVO courseVO = new CourseVO();
            courseVO.setId(item.getId());
            CourseClassVO courseClassVO = new CourseClassVO();
            CourseCourseVO courseCourseVO = new CourseCourseVO();
            CourseTeacherVO courseTeacherVO = new CourseTeacherVO();
            courseClassVO.setClassId(classEntity.getId());
            courseClassVO.setClassName(classEntity.getName());
            courseVO.setCourseClass(courseClassVO);
            courseCourseVO.setCourseId(courseEntity.getId());
            courseCourseVO.setCourseName(courseEntity.getName());
            courseVO.setCourseCourse(courseCourseVO);
            courseTeacherVO.setTeacherId(sysUserEntity.getUserId());
            courseTeacherVO.setTeacherName(sysUserEntity.getName());
            courseTeacherVO.setUserName(sysUserEntity.getUsername());
            courseVO.setCourseTeacher(courseTeacherVO);
            return courseVO;
        }).collect(Collectors.toList());
        Page<CourseVO> courseVOPage = new Page<>();
        BeanUtils.copyProperties(page, courseVOPage);
        courseVOPage.setRecords(courseVOS);
        return new PageUtils(courseVOPage);
    }

    @Override
    public ClassCourseSelectionVO getSelections(Long userId) {
        ClassCourseSelectionVO classCourseSelectionVO = new ClassCourseSelectionVO();
        DepartmentEntity department = departmentService.getByAdminId(userId);
        List<ClassEntity> classEntity = classService.getByDepartmentId(department.getId());
        List<CourseClassVO> courseClassVOList = classEntity.stream().map(item -> {
            CourseClassVO courseClassVO = new CourseClassVO();
            courseClassVO.setClassId(item.getId());
            courseClassVO.setClassName(item.getName());
            return courseClassVO;
        }).sorted(Comparator.comparing(CourseClassVO::getClassName)).collect(Collectors.toList());
        classCourseSelectionVO.setClassList(courseClassVOList);

        List<CourseEntity> courseEntityList = courseService.getByDepartmentId(department.getId());
        List<CourseCourseVO> courseVOList = courseEntityList.stream().map(item -> {
            CourseCourseVO courseCourseVO = new CourseCourseVO();
            courseCourseVO.setCourseId(item.getId());
            courseCourseVO.setCourseName(item.getName());
            return courseCourseVO;
        }).sorted(Comparator.comparing(CourseCourseVO::getCourseId)).collect(Collectors.toList());

        classCourseSelectionVO.setCourseList(courseVOList);

        List<SysUserEntity> userEntityList = sysUserService.getAllTeacher();
        List<CourseTeacherVO> teacherVOList = userEntityList.stream().map(item -> {
            CourseTeacherVO courseTeacherVO = new CourseTeacherVO();
            courseTeacherVO.setTeacherId(item.getUserId());
            courseTeacherVO.setTeacherName(item.getName());
            courseTeacherVO.setUserName(item.getUsername());
            return courseTeacherVO;
        }).sorted(Comparator.comparing(CourseTeacherVO::getTeacherName)).collect(Collectors.toList());
        classCourseSelectionVO.setTeacherList(teacherVOList);
        return classCourseSelectionVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveClassCourse(ClassCourseEntity classCourse, Long userId) {
        Long teacherId = classCourse.getTeacherId();
        SysUserEntity userEntity = sysUserService.getById(teacherId);
        List<Long> roleIds = sysUserRoleService.queryRoleIdList(userEntity.getUserId());
        SysRoleEntity role = sysRoleService.getByRoleName(RoleEnums.TEACHER.getRoleName());
        roleIds.add(role.getRoleId());
        Set<Long> set = new HashSet<>(roleIds);
        sysUserRoleService.saveOrUpdate(userEntity.getUserId(), set);

        Long courseId = classCourse.getCourseId();
        Long classId = classCourse.getClassId();
        ClassCourseEntity byClassIdAndCourseId = getByClassIdAndCourseId(classId, courseId);
        if (byClassIdAndCourseId != null) {
            throw new RRException("该班级课程已存在");
        }
        DepartmentEntity department = departmentService.getByAdminId(userId);
        classCourse.setDepartmentId(department.getId());
        this.save(classCourse);
    }

    @Override
    public ClassCourseEntity getByClassIdAndCourseId(Long classId, Long courseId) {
        return this.getOne(new LambdaQueryWrapper<ClassCourseEntity>().eq(ClassCourseEntity::getClassId, classId).eq(ClassCourseEntity::getCourseId, courseId));
    }

    @Override
    public List<ClassCourseEntity> getByTeacherId(Long userId) {
        return this.lambdaQuery().eq(ClassCourseEntity::getTeacherId, userId).list();
    }

    @Override
    public PageUtils queryPageMyClass(Map<String, Object> params) {
        LambdaQueryWrapper<ClassCourseEntity> wrapper = new LambdaQueryWrapper<>();
        //获取用户id
        Long userId = (Long) params.get(UserConstans.USER_ID_KEY);
        String key = (String) params.get("key");
        if(StringUtils.isNotBlank(key)){
            List<ClassEntity> classEntities = classService.likeByName(key);
            List<Long> classIds = classEntities.stream().map(ClassEntity::getId).collect(Collectors.toList());
            List<CourseEntity> courseEntityList = courseService.likeByName(key);
            List<Long> courseIds = courseEntityList.stream().map(CourseEntity::getId).collect(Collectors.toList());
            List<DepartmentEntity> departmentEntities = departmentService.likeByName(key);
            List<Long> departmentIds = departmentEntities.stream().map(DepartmentEntity::getId).collect(Collectors.toList());
            if(CollectionUtil.isNotEmpty(classIds)){
                wrapper.or().in(ClassCourseEntity::getClassId,classIds);
            }
            if(CollectionUtil.isNotEmpty(courseIds)){
                wrapper.or().in(ClassCourseEntity::getCourseId,courseIds);
            }
            if(CollectionUtil.isNotEmpty(departmentIds)){
                wrapper.or().in(ClassCourseEntity::getDepartmentId,departmentIds);
            }
        }
        IPage<ClassCourseEntity> page = this.page(
                new Query<ClassCourseEntity>().getPage(params),
                wrapper.in(ClassCourseEntity::getTeacherId, userId).orderByAsc(ClassCourseEntity::getId)
        );

        List<ClassCourseEntity> records = page.getRecords();
        Map<Long, ClassCourseEntity> classCourseMap = PojoUtils.listToMap(records, ClassCourseEntity::getId, Function.identity());
        List<Long> classCourseIds = getAnyIds(records, ClassCourseEntity::getId);
        List<WorkEntity> workList = workService.listByClassCourseIds(classCourseIds);


        //收集相关联所有系部id
        List<Long> deparmentIds = getAnyIds(records, ClassCourseEntity::getDepartmentId);
        //根据系部id查询系部
        List<DepartmentEntity> departmentEntityList = departmentService.listByIds(deparmentIds);
        Map<Long, DepartmentEntity> departmentEntityMap = ListToMap(departmentEntityList, DepartmentEntity::getId, Function.identity());
        //获取所有相关的课程id
        List<Long> courIds = getAnyIds(records, ClassCourseEntity::getCourseId);
        List<CourseEntity> courseEntityList = courseService.listByIds(courIds);
        Map<Long, CourseEntity> courseEntityMap = ListToMap(courseEntityList, CourseEntity::getId, Function.identity());
        //获取所有相关的班级id
        List<Long> classIds = getAnyIds(records, ClassCourseEntity::getClassId);
        //查询班级下的所有人
        List<StudentEntity> classStudents = studentService.getListByClassIds(classIds);
        Map<Long, List<StudentEntity>> studentGroupByClass = PojoUtils.listGroupByKey(classStudents, StudentEntity::getClassId);
        List<ClassEntity> classEntityList = classService.listByIds(classIds);
        Map<Long, ClassEntity> classEntityMap = ListToMap(classEntityList, ClassEntity::getId, Function.identity());
        Map<Long, List<WorkDetail>> listMap = new HashMap<>();
        if (CollectionUtil.isNotEmpty(workList)) {
            List<Long> workIds = PojoUtils.streamMapList(workList, WorkEntity::getId);
            List<WorkFinishStatusDetailEntity> workFinishStatusDetailEntities = workFinishStatusDetailService.listByWorkIds(workIds);
            Map<Long, List<WorkFinishStatusDetailEntity>> workFinishgroupByWorkId = PojoUtils.listGroupByKey(workFinishStatusDetailEntities, WorkFinishStatusDetailEntity::getWorkId);
            List<Long> questionBankIds = getAnyIds(workList, WorkEntity::getQuBankId);
            Map<Long, QuestionBankEntity> questionBankEntityMap = ListToMap(questionBankService.listByIds(questionBankIds), QuestionBankEntity::getId, Function.identity());

            listMap = workList.stream().map(item -> {
                ClassCourseEntity classCourseEntity = classCourseMap.get(item.getClassCourseId());
                Long classId = classCourseEntity.getClassId();
                List<StudentEntity> studentEntityList = studentGroupByClass.get(classId);
                List<WorkFinishStatusDetailEntity> workFinishStatusDetailEntities1 = workFinishgroupByWorkId.get(item.getId());
                int totalCountStudent = 0;
                int finishCountStudent = 0;
                if (CollectionUtil.isNotEmpty(studentEntityList)) {
                    totalCountStudent = studentEntityList.size();
                }
                if (CollectionUtil.isNotEmpty(workFinishStatusDetailEntities1)) {
                    finishCountStudent = workFinishStatusDetailEntities1.size();
                }
                int unFinishCountStudent = totalCountStudent - finishCountStudent;
                QuestionBankEntity questionBankEntity = questionBankEntityMap.get(item.getQuBankId());
                WorkDetail workDetail = new WorkDetail();
                workDetail.setWorkId(item.getId());
                workDetail.setClassCourseId(item.getClassCourseId());
                workDetail.setQuRepoName(questionBankEntity.getTitle());
                workDetail.setFinishCount(finishCountStudent);
                workDetail.setUnFinishCount(unFinishCountStudent);
                workDetail.setFinishRate(workDetail.getTotal().equals(0) ? 0 : workDetail.getFinishCount() * 100 / workDetail.getTotal());
                workDetail.setStatus(getFinshStatus(item.getStartTime(), item.getEndTime()));
                return workDetail;
            }).collect(Collectors.groupingBy(WorkDetail::getClassCourseId));
        }

        Map<Long, List<WorkDetail>> finalListMap = listMap;
        IPage<MyClassVO> convert = page.convert(item -> {
            DepartmentEntity department = departmentEntityMap.get(item.getDepartmentId());
            List<WorkDetail> workDetails = finalListMap.get(item.getId());
            CourseEntity courseEntity = courseEntityMap.get(item.getCourseId());
            ClassEntity classEntity = classEntityMap.get(item.getClassId());
            MyClassVO classVO = new MyClassVO();
            classVO.setClassCourseId(item.getId());
            classVO.setCourseId(item.getCourseId());
            classVO.setCourseName(courseEntity.getName());
            classVO.setId(item.getClassId());
            classVO.setName(classEntity.getName());
            classVO.setDepartmentId(item.getDepartmentId());
            classVO.setDepartmentName(department.getName());
            classVO.setHasWork(workDetails != null && workDetails.size() > 0);
            classVO.setWorkDetailList(workDetails);
            return classVO;
        });

        return new PageUtils(convert);
    }

    @Override
    public void submitWork(SubmitWork submitWork) {
        ClassCourseEntity classCourse = this.getById(submitWork.getClassCourseId());
        ClassEntity classEntity = classService.getById(classCourse.getClassId());
        int count = studentService.count(new LambdaQueryWrapper<StudentEntity>().eq(StudentEntity::getClassId, classEntity.getId()));
        WorkEntity workEntity = new WorkEntity();
        workEntity.setClassCourseId(submitWork.getClassCourseId());
        workEntity.setQuBankId(submitWork.getQuestionBankId());
        workEntity.setStartTime(submitWork.getDatetimeRange().get(0));
        workEntity.setEndTime(submitWork.getDatetimeRange().get(1));
        try {
            workService.save(workEntity);
        } catch (Exception e) {
            throw new RRException("作业已经发布，不能重复发布");
        }
    }

    @Override
    public List<ClassCourseEntity> getByClassId(Long classId) {
        return this.lambdaQuery().eq(ClassCourseEntity::getClassId, classId).list();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeClassCourseByIds(List<Integer> classCourseIds) {
        List<ClassCourseEntity> classCourseEntities = this.lambdaQuery().in(ClassCourseEntity::getId, classCourseIds).list();
        this.removeByIds(classCourseIds);
        List<Long> teacherIds = PojoUtils.streamMapList(classCourseEntities, ClassCourseEntity::getTeacherId);
        List<SysUserEntity> teachers = sysUserService.getByIds(teacherIds);
        for (SysUserEntity teacher : teachers) {
            Long userId = teacher.getUserId();
            List<ClassCourseEntity> teacherId = this.getByTeacherId(userId);
            if(CollectionUtil.isEmpty(teacherId)){
                //删除教师角色
                List<Long> roleIdList = sysUserRoleService.queryRoleIdList(userId);
                SysRoleEntity roleName = sysRoleService.getByRoleName(RoleEnums.TEACHER.getRoleName());
                roleIdList.removeIf(item -> item.equals(roleName.getRoleId()));
                sysUserRoleService.saveOrUpdate(userId,roleIdList);
            }
        }
    }

    private <T, R> List<R> getAnyIds(List<T> list, Function<? super T, ? extends R> mapper) {
        return list.stream()
                .map(mapper)
                .collect(Collectors.toList());
    }

    private <T, K, V> Map<K, V> ListToMap(List<T> list, Function<? super T, ? extends K> keyMapper,
                                          Function<? super T, ? extends V> valueMapper) {
        return list.stream().collect(Collectors.toMap(keyMapper, valueMapper));
    }

    private Integer getFinshStatus(Date startTime, Date endTime) {
        //判断当前时间是否小于开始时间
        if (System.currentTimeMillis() < startTime.getTime()) {
            return WorkStatusEnum.NOT_START.getCode();
        }
        //判断当前时间是否在开始时间和结束时间之间
        if (startTime.getTime() <= System.currentTimeMillis() && endTime.getTime() >= System.currentTimeMillis()) {
            return WorkStatusEnum.IN_PROGRESS.getCode();
        }

        //判断当前时间是否在结束时间之后
        if (endTime.getTime() < System.currentTimeMillis()) {
            return WorkStatusEnum.ENDED.getCode();
        }
        return WorkStatusEnum.NOT_START.getCode();
    }
}
